use std::{
    collections::{BTreeMap, HashSet},
    fmt,
};

use serde::{
    de::{MapAccess, Visitor},
    Deserialize,
};

pub fn count_provinces() -> String {
    let json_text = std::fs::read("./district.json").unwrap();
    let inputs: BTreeMap<i32, Input> = serde_json::from_slice(&json_text).unwrap();

    let mut out = Vec::new();
    for input in inputs.into_values() {
        let mut buf = Vec::<HashSet<String>>::new();
        'a: for i in input.0 {
            for j in buf.iter_mut() {
                if has_intersection(&i, &j) {
                    i.iter().for_each(|x| {
                        j.insert(x.to_string());
                    });
                    break 'a;
                }
            }
            buf.push(i);
        }
        out.push(buf.len().to_string());
    }
    out.join(",")
}

fn has_intersection<T: std::hash::Hash + Eq>(set1: &HashSet<T>, set2: &HashSet<T>) -> bool {
    for item in set1 {
        if set2.contains(item) {
            return true;
        }
    }
    false
}

pub struct Input(Vec<HashSet<String>>);

impl<'de> Deserialize<'de> for Input {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct MyMapVisitor;

        impl<'de> Visitor<'de> for MyMapVisitor {
            type Value = Input;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a very special map")
            }

            fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
            where
                M: MapAccess<'de>,
            {
                let mut map = Vec::with_capacity(access.size_hint().unwrap_or(0));

                while let Some((key, mut value)) = access.next_entry::<String, HashSet<String>>()? {
                    value.insert(key);
                    map.push(value);
                }

                Ok(Input(map))
            }
        }
        deserializer.deserialize_map(MyMapVisitor)
    }
}
